#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <vector>

/**
 * @brief 示例类，包含数据和字符串成员
 * 
 * 构造和析构时会输出信息，便于跟踪对象生命周期
 */
class Temp {
private:
    size_t _data;      // 数值数据
    std::string _str;  // 字符串数据
public:
    /**
     * @brief 构造函数
     * @param data 数值数据
     * @param str 字符串数据
     */
    Temp(size_t data, const std::string str):_data(data), _str(str) {
        std::cout << "构造temp" << this << std::endl;
    }
    
    /**
     * @brief 析构函数
     * 
     * 输出对象销毁信息
     */
    ~Temp() {std::cout << "析构temp" << this << std::endl;}
    
    /**
     * @brief 获取数值数据
     * @return 数值数据的副本
     */
    size_t get_data() const {return _data; }
    
    /**
     * @brief 获取字符串数据的常量引用
     * @return 字符串数据的常量引用
     */
    const std::string& get_str() const {return _str; }
};

/**
 * @brief 打印Temp对象信息的函数
 * @param tmp 要打印的Temp对象引用
 */
void print( Temp &tmp) {
    std::cout << tmp.get_data() << tmp.get_str() << std::endl;
}

// 定义函数包装器类型，用于存储无参数的可调用对象
using Functor = std::function<void()>;

int main()
{
    // 创建一个包含1个元素的函数包装器向量
    std::vector<Functor> arry(1);
    
    {
        // 创建临时对象tmp，作用域仅限于内部代码块
        Temp tmp(99, "nihao");
        
        // 使用std::bind绑定print函数和tmp的引用
        // 注意：使用std::move是不必要的，因为std::ref返回的是reference_wrapper对象
        // 这里应该直接使用std::ref(tmp)
        Functor f = std::bind(print, std::move(std::ref(tmp)));
        
        // 将函数包装器移动到向量中
        arry[0] =  std::move(f);
        
        // 【重要】tmp在代码块结束时会被销毁
        // 但arry[0]中存储的函数包装器仍然持有对tmp的引用
    }
    
    // 【危险】调用函数包装器，此时tmp已被销毁
    // 这会导致访问悬挂引用，产生未定义行为
    arry[0]();
    
    return 0;
}